// BSD 3-Clause License
// Copyright (c) 2024, Tecorigin Co., Ltd. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// ...

#ifndef UAL_OPS_CONV_FORWARD_CONV_FORWARD_HPP_
#define UAL_OPS_CONV_FORWARD_CONV_FORWARD_HPP_

#include "ual/kernel/conv_forward/conv_forward.h"
#include "ual/com/log.h"
#include "ual/args/conv_args.h"
#include "ual/ops/base_op.hpp"
#include "ual/ops/conv_forward/find_conv_forward.h"

using tecoal::ual::args::ConvFwdArgs;
using tecoal::ual::args::ConvFwdPatchArgs;
using namespace tecoal::ual::kernel;

namespace tecoal {
namespace ual {
namespace ops {

enum ConvType : uint16_t {};

struct ConvFType {
    using ArgsType = ConvFwdArgs;
    using PatchType = ConvFwdPatchArgs;
    using RetType = void;
    using PImplType = void (*)(ArgsType);
    using AlgoType = ConvType;
};

static ConvFType::PImplType ConvFwdAlgos[] = {
    tecoKernelConvFwdFT16SingleThread,    // Single-core implementation
    tecoKernelConvFwdFT16MultiThreads,   // Multi-core implementation
    tecoKernelConvFwdFT16DMA,            // DMA for efficient data transfer
    tecoKernelConvFwdFT16SIMD,           // SIMD for FP16 convolution
    tecoKernelConvFwdFT16Matmul,         // SDAAC matmul API
    tecoKernelConvFwdFT16Broadcast,      // Broadcast for data reuse
    tecoKernelConvFwdFT16DoubleBuffer,   // Double buffering technique
    tecoKernelConvFwdNodilationBaseline,  // Baseline for comparison
    tecoKernelConvFwdNodilationALGO47,   // Algorithm 47
};

static const char *convFwdDescription[] = {
    "tecoKernelConvFwdFT16SingleThread", "tecoKernelConvFwdFT16MultiThreads",
    "tecoKernelConvFwdFT16DMA",          "tecoKernelConvFwdFT16SIMD",
    "tecoKernelConvFwdFT16Matmul",       "tecoKernelConvFwdFT16Broadcast",
    "tecoKernelConvFwdFT16DoubleBuffer", "tecoKernelConvFwdNodilationBaseline",
    "tecoKernelConvFwdNodilationALGO47"
};

struct ConvFwdOp : public BaseOp<ConvFwdOp, ConvFType> {
 public:
    using ArgsType = typename ConvFType::ArgsType;
    using PatchType = typename ConvFType::PatchType;
    using RetType = typename ConvFType::RetType;
    using PImplType = typename ConvFType::PImplType;
    using AlgoType = typename ConvFType::AlgoType;

    static const char *name() { return "Conv forward"; }

    Status getWorkspace(const PatchType *args, size_t *size) {
        *size = findConvForwardWorkspace(args);
        return Status::SUCCESS;
    }

    Status findImpl(const PatchType *args) {
        ConvFwdBranch branch = findConvForwardBranch(args);
        if (branch == ConvFwdBranch::CONV_FWD_END) {
            return Status::NOT_IMPLEMENTED;
        }
        int index = static_cast<int>(branch);
        setInstance(ConvFwdAlgos[index], convFwdDescription[index]);
        return Status::SUCCESS;
    }
};

}  // namespace ops
}  // namespace ual
}  // namespace tecoal

#endif  // UAL_OPS_CONV_FORWARD_CONV_FORWARD_HPP_
